package com.github.m6d21.conflict.config;

import com.github.m6d21.conflict.util.FileUtil;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import java.io.File;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *<p>
 *配置文件读取类
 *</p>
 *
 * @author liuyang
 * @date 2018/12/12 Wed 14:05:00
 * @since 1.0.0
 */
public class ConflictScanConfigReader {

    private static final Logger LOG = LoggerFactory.getLogger(ConflictScanConfigReader.class);

    private ConflictScanConfigReader() {
    }

    private String propertiesPath = null;

    public static final ConflictScanConfigReader getInstance() {
        ConflictScanConfigReader reader = new ConflictScanConfigReader();
        return reader;
    }

    public ConflictScanConfigReader propertiesPath(String propertiesPath) {
        this.propertiesPath = propertiesPath;
        return this;
    }

    public ScanConfig getScanConfig() {
        return getScanConfig(propertiesPath);
    }

    /**
     * properties转为包装类
     */
    private ScanConfig getScanConfig(String propertiesPath) {
        if (StringUtils.isEmpty(propertiesPath)) {
            propertiesPath = getDefaultScanPath();
        }
        Properties properties = findProperties(propertiesPath);
        ScanConfig config = new ScanConfig();
        convert2ScanConfig(properties, config);
        return config;
    }

    private void convert2ScanConfig(Properties properties, ScanConfig config) {
        try {
            config.scanPaths = toStringArray(
                (String) properties.get(ConflictScanConfigConstant.SCAN_PATHS));
            config.scanPackages = toStringArray(
                (String) properties.get(ConflictScanConfigConstant.SCAN_PACKAGES));
            config.onlyShowDiffClass = toBoolean(
                (String) properties.get(ConflictScanConfigConstant.ONLY_SHOW_DIFF_CLASS));
            config.includeKeyword = toStringArray(
                (String) properties.get(ConflictScanConfigConstant.INCLUDE_KEY_WORD));
            config.excludeKeyword = toStringArray(
                (String) properties.get(ConflictScanConfigConstant.EXCLUDE_KEY_WORD));
        } catch (Exception e) {
            LOG.error("读取属性时遇到异常，检查配置properties文件：{}", e);
        }
    }

    private String[] toStringArray(String value) {
        if (StringUtils.isBlank(value)) {
            return null;
        }
        Iterator<String> iterator = Splitter.on(",").trimResults().split(value).iterator();
        List<String> list = Lists.newArrayList(iterator);
        int size = list.size();
        return list.toArray(new String[size]);
    }

    private Boolean toBoolean(String value) {
        if ("true".equals(value)) {
            return true;
        } else if ("false".equals(value)) {
            return false;
        }
        return null;
    }

    /**
     * 获取properties文件扫描路径
     */
    private String getDefaultScanPath() {
        //先获取classpath路径
        String path = FileUtil.getClasspath();
        if (StringUtils.isEmpty(path)) {
            try {
                LOG.info("jar包环境下，将扫描当前目录下的properties文件, 并尝试读取（扫描配置属性）");
                //classpath路径获取失败后，获取当前路径
                path = new File("").getAbsolutePath();
            } catch (Exception e) {
                path = "";
                LOG.error("获取当前路径失败GG: {}", e);
            }
        }
        return path;
    }

    /**
     *遍历目录下的properties
     */
    private Properties findProperties(String propertiesPath) {
        Set<File> foundFileSet = FileUtil.findFiles(propertiesPath, this::isPropertiesFile);
        Set<Properties> propertiesSet = new HashSet<>(foundFileSet.size());
        for (File file : foundFileSet) {
            LOG.info("扫描到配置文件：{}", file.getAbsolutePath());
            Properties p = FileUtil.readReadProperties(file.getAbsolutePath());
            if (p != null) {
                propertiesSet.add(p);
            }
        }
        int size = propertiesSet.size();
        return FileUtil.mergeProperties(propertiesSet.toArray(new Properties[size]));
    }

    private boolean isPropertiesFile(File file) {
        return FileUtil.exists(file) && file.isFile() && file.getName().endsWith(FileUtil.PROPERTIES_TYPE);
    }

    public class ScanConfig {

        private String[] scanPaths;
        private String[] scanPackages;
        private Boolean onlyShowDiffClass;
        private String[] includeKeyword;
        private String[] excludeKeyword;

        public String[] getScanPaths() {
            return scanPaths;
        }

        public void setScanPaths(String[] scanPaths) {
            this.scanPaths = scanPaths;
        }

        public String[] getScanPackages() {
            return scanPackages;
        }

        public void setScanPackages(String[] scanPackages) {
            this.scanPackages = scanPackages;
        }

        public Boolean getOnlyShowDiffClass() {
            return onlyShowDiffClass;
        }

        public void setOnlyShowDiffClass(Boolean onlyShowDiffClass) {
            this.onlyShowDiffClass = onlyShowDiffClass;
        }

        public String[] getIncludeKeyword() {
            return includeKeyword;
        }

        public void setIncludeKeyword(String[] includeKeyword) {
            this.includeKeyword = includeKeyword;
        }

        public String[] getExcludeKeyword() {
            return excludeKeyword;
        }

        public void setExcludeKeyword(String[] excludeKeyword) {
            this.excludeKeyword = excludeKeyword;
        }
    }
}
